﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;

namespace DDDB
{
    /// <summary>
    /// boom过滤器，用来快速判断一个key 一定不存在 或者 可能存在
    /// </summary>
    public class BoomFilter:IDisposable
    {
        byte[] bfdata;
        public int UseBit
        {
            get;
            private set;
        }
   
        public uint BitMask
        {
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            get
            {
                return _bitmask;
            }
        }
        public int MemorySize
        {
            get
            {
                return bfdata.Length;
            }
        }
        uint _bitmask;
        System.IO.FileStream? sync;
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public uint GetIndexWithMask(uint v)
        {
            return v & _bitmask;
        }
        public BoomFilter(int bit, string? syncfile = null)
        {
            if (bit < 24 || bit > 32)
                throw new Exception("use bit 24~32");


            _bitmask = 0;
            for (var i = 0; i < bit; i++)
            {
                _bitmask |= (uint)(1 << i);
            }

            UseBit = bit;
            bfdata = new byte[((long)1 << bit) / 8];

         
            if (syncfile != null)
            {
                if (System.IO.File.Exists(syncfile) == false)
                {
                    sync = System.IO.File.Open(syncfile, FileMode.OpenOrCreate);
                    sync.Write(bfdata, 0, bfdata.Length);
                    sync.Position = 0;
                }
                else
                {
                    sync = System.IO.File.Open(syncfile, FileMode.Open);
                    sync.Read(bfdata, 0, bfdata.Length);
                    sync.Position = 0;
                }
            }

        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void Set(uint index)
        {
            uint pos = (index / 8);
            int bitpos = (int)(index % 8);
            bfdata[pos] |= (byte)(1 << bitpos);
            if (sync != null)
            {
                sync.Position = pos;
                sync.WriteByte(bfdata[pos]);
            }
        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public bool Get(uint index)
        {
            uint pos = (index / 8);
            int bitpos = (int)(index % 8);
            return (bfdata[pos] & (1 << bitpos)) > 0;
        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void UnSet(uint index)
        {
            uint pos = (index / 8);
            int bitpos = (int)(index % 8);
            bfdata[pos] &= (byte)(~(1 << bitpos));
            sync.Position = pos;
            sync.WriteByte(bfdata[pos]);
            if (sync != null)
            {
                sync.Position = pos;
                sync.WriteByte(bfdata[pos]);
            }
        }

        public void Dispose()
        {
            if(sync!= null)
            {
                sync.Close();
            }
        }
    }
}
